/**
 * \file Point2D.h
 * \brief Point2D definition and declaration class
 * \author Edouard ROGE
 * \date 12 septembre 2010
 */

#ifndef _POINT2D_
#define _POINT2D_

#include "Core/Memory/HeapObject.h"

namespace Math
{
	namespace M2D
	{

		/**
		* \class Point2D
		* \brief class with template to instantiate a 2D point with float or int
		*/
		template < class T >
		class Point2D : public Memory::HeapObject
		{
		public:
			/**
			* \union union
			* \brief union of 2 value (x and y) and a array with 2 elements
			*/
			union
			{
				/**
				* \struct struct
				* \brief x and y
				*/
				struct
				{
					/** x */
					T x;
					/** y */
					T y;
				};
				/** array of 2 elements */
				T	Value[2];
			};

		public:
			/**
			* \fn Point2D();
			* \brief Default constructor
			*/
			Point2D();

			/**
			* \fn Point2D(T _x, T _y);
			* \param _x copy _x in x
			* \param _y copy _y in y
			* \brief Constructor with parameter
			*/
			Point2D(T _x, T _y);

			/**
			* \fn Point2D(const Point2D<T> & p);
			* \param p Point to copy
			* \brief Copy constructor
			*/
			Point2D(const Point2D<T> & p);

			/**
			* \fn ~Point2D();
			* \brief Destructor
			*/
			~Point2D();

			/**
			* \fn void Set(T _x, T _y);
			* \param _x copy _x in x
			* \param _y copy _y in y
			* \brief Set 2d Point values
			*/
			void Set(T _x, T _y);

			/**
			* \fn operator T* ();
			* \return the 2d point value
			* \brief retrieve the 2d point value in a array of T.
			* Useful for casting
			*/
			operator T* ();

			/**
			* \fn operator const T* () const
			* \return the 2d point value
			* \brief retrieve the 2d point value in a array of T.
			* Useful for casting
			*/
			operator const T* () const;

			/**
			* \fn Point2D<T> & operator = (const Point2D<T> & _o);
			* \param _o copy _o in (*this)
			* \return (*this) with the new value
			* \brief operator =
			*/
			Point2D<T> & operator = (const Point2D<T> & _o);

			/**
			* \fn template < class T1 > friend bool operator == (const Point2D<T1> & _o1, const Point2D<T1> & _o2);
			* \param _o1 2d point
			* \param _o2 2d point
			* \return true if _o1 is equal to _o2
			*/
			template < class T1 > friend bool operator == (const Point2D<T1> & _o1, const Point2D<T1> & _o2);

			/**
			* \fn template < class T1 > friend bool operator != (const Point2D<T1> & _o1, const Point2D<T1> & _o2);
			* \param _o1 2d point
			* \param _o2 2d point
			* \return true if _o1 is not equal to _o2
			*/
			template < class T1 > friend bool operator != (const Point2D<T1> & _o1, const Point2D<T1> & _o2);
		};

		/** Point2D of float */
		typedef Point2D<float>	Point2f;

		/** Point2D of integer */
		typedef Point2D<int>	Point2i;

		template < class T >
		Point2D< T >::Point2D()
			:x(0), y(0)
		{

		}

		template < class T >
		Point2D< T >::Point2D(T _x, T _y)
			: x(_x), y(_y)
		{

		}

		template < class T >
		Point2D< T >::Point2D(const Point2D<T> & p)
			: x(p.x), y(p.y)
		{

		}

		template < class T >
		Point2D< T >::~Point2D()
		{

		}

		template < class T >
		void Point2D< T >::Set(T _x, T _y)
		{
			x = _x;
			y = _y;
		}

		template < class T >
		Point2D< T >:: operator T* ()
		{
			return Value;
		}

		template < class T >
		Point2D< T >::operator const T* () const
		{
			return Value;
		}

		template < class T >
		Point2D<T> & Point2D< T >::operator = (const Point2D<T> & _o)
		{
			x = _o.x;
			y = _o.y;
			return (*this);
		}
	}
}

/**
 * \fn template < class T1 > bool operator == (const Math::M2D::Point2D<T1> & _o1, const Math::M2D::Point2D<T1> & _o2);
 * \param _o1 2d point
 * \param _o2 2d point
 * \return true if _o1 is equal to _o2
 */
template < class T1 >
bool operator == (const Math::M2D::Point2D<T1> & _o1, const Math::M2D::Point2D<T1> & _o2)
{
	return (_o1.x == _o2.x && _o1.y == _o2.y);
}

/**
 * \fn template < class T1 > bool operator != (const Math::M2D::Point2D<T1> & _o1, const Math::M2D::Point2D<T1> & _o2);
 * \param _o1 2d point
 * \param _o2 2d point
 * \return true if _o1 is not equal to _o2
 */
template < class T1 >
bool operator != (const Math::M2D::Point2D<T1> & _o1, const Math::M2D::Point2D<T1> & _o2)
{
	return !(_o1 == _o2);
}

#endif // _POINT2D_
